package com.gitee.grassprogramming.orm.util;


import com.gitee.grassprogramming.orm.base.*;
import com.gitee.grassprogramming.orm.design.BaseEntity;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.List;
import java.util.Map;

/**
 * Created by paul on 2018/12/31.
 */

public class DBUtil {
    private PreCommand preCommand;
    private boolean traceSQL;
    public DBUtil(){
        preCommand = new PreCommand();
        traceSQL = false;
    }
    public static void init(Class runClass) throws Exception{
        ClassCacheManage.initClassCache(runClass);
    }
    public void OpenTrace(){
        traceSQL = true;
    }
    public void CloseTrace(){
        traceSQL = false;
    }
    //增
    public <T extends BaseEntity> boolean insert(T entity) throws Exception{
        Command command = preCommand.initInsert(entity);
        command.setTraceSQL(traceSQL);
        return command.executeCommand();
    }

    public <T extends BaseEntity> boolean insert(T entity,DriverManagerDataSource dataSource) throws Exception{
        Command command = preCommand.initInsert(entity);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.executeCommand();
    }
    //批量插入
    public <T extends BaseEntity> void insertBatch(List<T> batchList) throws Exception{
        DriverManagerDataSource transitionDataSource = getDataSource();
        executeTransition(transitionDataSource, new TransitionAction() {
            @Override
            public void doTransitionOption(DriverManagerDataSource dataSource){
                try {
                    for (T entity:batchList) {
                        insert(entity,dataSource);
                    }
                }
                catch (Exception e){
                    e.printStackTrace();
                    throw new RuntimeException();
                }
            }
        });
    }

    //删
    public <T extends BaseEntity> boolean delete(T entity) throws Exception{
        Command command = preCommand.initDelete(entity);
        command.setTraceSQL(traceSQL);
        return command.executeCommand();
    }

    public <T extends BaseEntity> boolean delete(T entity,DriverManagerDataSource dataSource) throws Exception{
        Command command = preCommand.initDelete(entity);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.executeCommand();
    }

    //改
    public <T extends BaseEntity> boolean update(T entity) throws Exception
    {
        Command command = preCommand.initUpdate(entity);
        command.setTraceSQL(traceSQL);
        return command.executeCommand();
    }
    public <T extends BaseEntity> boolean update(T entity,DriverManagerDataSource dataSource) throws Exception
    {
        Command command = preCommand.initUpdate(entity);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.executeCommand();
    }

    public <T extends BaseEntity> boolean update(Object entity,Class<T> tClass) throws Exception
    {
        Command command = preCommand.initUpdate(entity,tClass);
        command.setTraceSQL(traceSQL);
        return command.executeCommand();
    }

    public <T extends BaseEntity> boolean update(Object entity,Class<T> tClass,DriverManagerDataSource dataSource) throws Exception
    {
        Command command = preCommand.initUpdate(entity,tClass);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.executeCommand();
    }

    //查
    //获取表数据总数量
    public <T extends BaseEntity> int getCount(Class<T> tClass) throws Exception{
        Command command = preCommand.initCount(tClass);
        command.setTraceSQL(traceSQL);
        SqlRowSet result = command.executeScarCommand();
        if(result.next()){
            return  result.getInt(1);
        }else{
            throw new RuntimeException("no result");
        }
    }
    public <T extends BaseEntity> int getCount(Class<T> tClass,DriverManagerDataSource dataSource) throws Exception{
        Command command = preCommand.initCount(tClass);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        SqlRowSet result = command.executeScarCommand();
        if(result.next()){
            return  result.getInt(1);
        }else{
            throw new RuntimeException("no result");
        }
    }
    //单条记录（主键查找）
    public <T extends BaseEntity> T findOne(String keyGuid, Class<T> tClass) throws Exception{
        Command command = preCommand.initFindOne(keyGuid,tClass);
        command.setTraceSQL(traceSQL);
        return command.queryCommand(tClass);
    }
    public <T extends BaseEntity> T findOne(String keyGuid, Class<T> tClass,DriverManagerDataSource dataSource) throws Exception{
        Command command = preCommand.initFindOne(keyGuid,tClass);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.queryCommand(tClass);
    }
    //查单条记录（根据其他键查找）
    public <T extends BaseEntity> T findOne(String keyName,String keyGuid, Class<T> tClass) throws Exception{
        Command command = preCommand.initFindOne(keyName,keyGuid,tClass);
        command.setTraceSQL(traceSQL);
        return command.queryCommand(tClass);
    }
    public <T extends BaseEntity> T findOne(String keyName,String keyGuid, Class<T> tClass,DriverManagerDataSource dataSource) throws Exception{
        Command command = preCommand.initFindOne(keyName,keyGuid,tClass);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.queryCommand(tClass);
    }
    //查单条记录(根据条件查找)
    public <T extends BaseEntity> T findOne(String where, Object[] args,Class<T> tClass) throws Exception{
        List<T> list = findList("*",where,args,"",tClass);
        if(list.size()>0){
            return list.get(0);
        }else{
            return null;
        }
    }
    public <T extends BaseEntity> T findOne(String where, Object[] args,Class<T> tClass,DriverManagerDataSource dataSource) throws Exception{
        List<T> list = findList("*",where,args,"",tClass,dataSource);
        if(list.size()>0){
            return list.get(0);
        }else{
            return null;
        }
    }
    //列表
    public <T extends BaseEntity> List<T> findList(String columns, String where,Object[] args,String orderBy,Class<T> tClass) throws Exception{
        Command command = preCommand.initFindList(columns,where,args,orderBy,tClass);
        command.setTraceSQL(traceSQL);
        return command.queryListCommand(tClass);
    }
    public <T extends BaseEntity> List<T> findList(String columns, String where,Object[] args,String orderBy,Class<T> tClass,DriverManagerDataSource dataSource) throws Exception{
        Command command = preCommand.initFindList(columns,where,args,orderBy,tClass);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.queryListCommand(tClass);
    }
    //分页查找
    public <T extends BaseEntity> List<T> findPage(String columns, String where,Object[] args,String orderBy,int pageIndex,int pageSize,Class<T> tClass) throws Exception{
        Command command = preCommand.initFindPage(columns,where,args,orderBy,pageIndex,pageSize,tClass);
        command.setTraceSQL(traceSQL);
        return command.queryListCommand(tClass);
    }
    public <T extends BaseEntity> List<T> findPage(String columns, String where,Object[] args,String orderBy,int pageIndex,int pageSize,Class<T> tClass,DriverManagerDataSource dataSource) throws Exception{
        Command command = preCommand.initFindPage(columns,where,args,orderBy,pageIndex,pageSize,tClass);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.queryListCommand(tClass);
    }
    //多表联查
    public List<Map<String,Object>> findView(String viewName,String columns, String where,Object[] args,String orderBy) throws  Exception{
        Command command = preCommand.initFindView(viewName,columns,where,args,orderBy);
        command.setTraceSQL(traceSQL);
        return command.queryViewCommand();
    }
    public List<Map<String,Object>> findView(String viewName,String columns, String where,Object[] args,String orderBy,DriverManagerDataSource dataSource) throws  Exception{
        Command command = preCommand.initFindView(viewName,columns,where,args,orderBy);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.queryViewCommand();
    }
    //多表联查(分页)
    public List<Map<String,Object>> findView(String viewName,String columns, String where, Object[] args,String orderBy,int pageIndex,int pageSize) throws  Exception{
        Command command = preCommand.initFindViewPage(viewName,columns,where,args,orderBy,pageIndex,pageSize);
        command.setTraceSQL(traceSQL);
        return command.queryViewCommand();
    }
    public List<Map<String,Object>> findView(String viewName,String columns, String where, Object[] args,String orderBy,int pageIndex,int pageSize,DriverManagerDataSource dataSource) throws  Exception{
        Command command = preCommand.initFindViewPage(viewName,columns,where,args,orderBy,pageIndex,pageSize);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.queryViewCommand();
    }

    //执行sql语句
    public boolean executeSQL(String sql,Object[] args){
        Command command = preCommand.initExecuteSQL(sql,args);
        command.setTraceSQL(traceSQL);
        return command.executeCommand();
    }

    public boolean executeSQL(String sql,Object[] args,DriverManagerDataSource dataSource){
        Command command = preCommand.initExecuteSQL(sql,args);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        return command.executeCommand();
    }

    //查找单个字段
    public String executeSQLToString(String sql,Object[] args){
        Command command = preCommand.initExecuteSQL(sql,args);
        command.setTraceSQL(traceSQL);
        SqlRowSet result = command.executeScarCommand();
        if(result.next()){
            return  result.getString(1);
        }else{
            throw new RuntimeException("no result");
        }
    }

    public String executeSQLToString(String sql,Object[] args,DriverManagerDataSource dataSource){
        Command command = preCommand.initExecuteSQL(sql,args);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        SqlRowSet result = command.executeScarCommand();
        if(result.next()){
            return  result.getString(1);
        }else{
            throw new RuntimeException("no result");
        }
    }

    public int executeSQLToInt(String sql,Object[] args){
        Command command = preCommand.initExecuteSQL(sql,args);
        command.setTraceSQL(traceSQL);
        SqlRowSet result = command.executeScarCommand();
        if(result.next()){
            return  result.getInt(1);
        }else{
            throw new RuntimeException("no result");
        }

    }

    public int executeSQLToInt(String sql,Object[] args,DriverManagerDataSource dataSource){
        Command command = preCommand.initExecuteSQL(sql,args);
        command.setTraceSQL(traceSQL);
        command.setDataSource(dataSource);
        SqlRowSet result = command.executeScarCommand();
        if(result.next()){
            return  result.getInt(1);
        }else{
            throw new RuntimeException("no result");
        }
    }

    //事物
    public void executeTransition(DriverManagerDataSource dataSource,TransitionAction action){
        TransactionTemplate transTemplate = new TransactionTemplate(new DataSourceTransactionManager(dataSource));
        Object isTransitionSuccess = transTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
                action.doTransitionOption(dataSource);
                return null;
            }
        });
    }

    public DriverManagerDataSource getDataSource(){
        return Config.GetInstance().getDataSource();
    }

    public DriverManagerDataSource getDataSource(String url,String username,String password,String driverClassName){
        return Config.GetInstance().getDataSource(url,username,password,driverClassName);
    }
}
